package com.sanyuan.cloud.module.system.service.ip.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.sanyuan.cloud.framework.common.util.json.JsonUtils;
import com.sanyuan.cloud.module.system.controller.app.ip.dto.GaodeAreaLocationDTO;
import com.sanyuan.cloud.module.system.controller.app.ip.vo.AreaLocationReqVO;
import com.sanyuan.cloud.module.system.controller.app.ip.vo.AreaLocationRespVO;
import com.sanyuan.cloud.module.system.controller.app.ip.vo.DistrictRespVO;
import com.sanyuan.cloud.module.system.service.ip.AppAreaService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.List;

import static com.sanyuan.cloud.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.sanyuan.cloud.module.infra.enums.ErrorCodeConstants.NONGMO_THIRD_API_FAIL;
import static com.sanyuan.cloud.module.system.enums.nongmo.GaodeApiEnums.*;
import static com.sanyuan.cloud.module.system.enums.nongmo.NongmoRedisKeyConstants.DISTRICT;

/**
 * @Description:
 * @Author: wuyuwei
 * @Date: 2025/4/3
 */
@Slf4j
@Service
@RefreshScope
public class AppAreaServiceImpl implements AppAreaService {

    @Resource
    @Qualifier("restTemplate")
    private RestTemplate restTemplate;

    @Resource
    private RedisTemplate<String,String> redisTemplate;

    @Value("${nongmo.gaode.api.key}")
    private String key;

    @Value("${nongmo.gaode.api.districturl:https://restapi.amap.com/v3/config/district}")
    private String districturl;

    @Value("${nongmo.gaode.api.geourl:https://restapi.amap.com/v3/geocode/geo}")
    private String geourl;


    @Override
    public List<DistrictRespVO> getDistrict(String citycode) {
        if (StrUtil.isBlank(citycode)){
            // 默认查询全国省-市-区
            citycode = CONTRY_CODE.getValue();
        }
        String value = redisTemplate.opsForValue().get(DISTRICT + citycode);
        if (StrUtil.isNotBlank(value)){
            log.info("---- getDistrict from redis [{}]", citycode);
            return JSONUtil.toList(value, DistrictRespVO.class);
        }else {
            String url = packBaseUrl(districturl);
            StringBuilder sb = new StringBuilder(url);

            sb.append("&keywords=").append(citycode);
            if (citycode.equals(CONTRY_CODE.getValue())){
                sb.append("&subdistrict=2");
            }else {
                sb.append("&subdistrict=3");
            }
            List<DistrictRespVO> list = httpRequest(sb.toString(), null, DistrictRespVO.class, DISTRICTS.getValue());
            list.parallelStream().forEach(data->{
                if (StrUtil.isNotBlank(data.getCenter())){
                    String[] split = data.getCenter().split(",");
                    data.setLongitude(split[0]);
                    data.setLatitude(split[1]);
                    if (CollUtil.isNotEmpty(data.getDistricts())){
                        setLongitudeAndLatitude(data.getDistricts());
                    }
                }
            });
            redisTemplate.opsForValue().set(DISTRICT + citycode, JSONUtil.toJsonStr(list));
            log.info("---- getDistrict from gaode api [{}]", citycode);
            return list;
        }
    }

    private void setLongitudeAndLatitude(List<DistrictRespVO> districts){
        if (CollUtil.isEmpty(districts)){
            return;
        }
        districts.parallelStream().forEach(item->{
            if (StrUtil.isNotBlank(item.getCenter())){
                String[] split = item.getCenter().split(",");
                item.setLongitude(split[0]);
                item.setLatitude(split[1]);
                if (CollUtil.isNotEmpty(item.getDistricts())){
                    setLongitudeAndLatitude(item.getDistricts());
                }
            }
        });
    }

    @Override
    public AreaLocationRespVO getAreaLocation(AreaLocationReqVO reqVO) {
        String url = packBaseUrl(geourl);
        StringBuilder sb = new StringBuilder(url);
        sb.append("&address=").append(reqVO.getAddress());
        if (StrUtil.isNotBlank(reqVO.getCity())){
            sb.append("&city=").append(reqVO.getCity());
        }
        List<AreaLocationRespVO> list = httpRequest(sb.toString(), null, AreaLocationRespVO.class, GEOCODES.getValue());
        return list.get(0);
    }

    /**
     * 封装url
     * @param url
     * @return
     */
    private String packBaseUrl(String url){
        StringBuilder sb = new StringBuilder(url);
        sb.append("?key=").append(key);
        return sb.toString();
    }

    /**
     * 行政区域查询
     *
     * @param url 请求 url
     * @param req 对应请求的请求参数
     * @param respClass 对应请求的响应 class
     * @param <Req> 每个请求的请求结构 Req DTO
     * @param <Resp> 每个请求的响应结构 Resp DTO
     */
    private <Req, Resp> Resp httpDistrictRequest(String url, Req req, Class<Resp> respClass) {
        // 请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        log.info("[httpRequest][请求参数({})]", url);

        // 发送请求
        ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, null, String.class);
        log.info("[httpRequest][的响应结果({})]", responseEntity);
        // 处理响应
        if (!responseEntity.getStatusCode().is2xxSuccessful()) {
            throw exception(NONGMO_THIRD_API_FAIL);
        }
        String body = responseEntity.getBody();
        JSONObject parseObj = JSONUtil.parseObj(body);
        String status = parseObj.getStr("status");
        if (!status.equals(SUCCESS.getValue())){
            log.error("调用高德api失败，info:{}",parseObj.getStr("info"));
            throw exception(NONGMO_THIRD_API_FAIL);
        }
        JSONArray geocodes = parseObj.getJSONArray("geocodes");
        List<GaodeAreaLocationDTO> list = geocodes.toList(GaodeAreaLocationDTO.class);
        if (CollUtil.isEmpty(list)){
            return null;
        }
        return JsonUtils.parseObject(JSONUtil.toJsonStr(list.get(0)), respClass);
    }

    /**
     * 请求地理信息
     *
     * @param url 请求 url
     * @param req 对应请求的请求参数
     * @param respClass 对应请求的响应 class
     * @param <Req> 每个请求的请求结构 Req DTO
     * @param <Resp> 每个请求的响应结构 Resp DTO
     */
    private <Req, Resp> List<Resp> httpRequest(String url, Req req, Class<Resp> respClass, String dataKey) {
        // 请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        log.info("[httpRequest][请求参数({})]", url);

        // 发送请求
        ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, null, String.class);
        log.info("[httpRequest][的响应结果({})]", responseEntity);
        // 处理响应
        if (!responseEntity.getStatusCode().is2xxSuccessful()) {
            throw exception(NONGMO_THIRD_API_FAIL);
        }
        String body = responseEntity.getBody();
        JSONObject parseObj = JSONUtil.parseObj(body);
        String status = parseObj.getStr("status");
        if (!status.equals(SUCCESS.getValue())){
            log.error("调用高德api失败，info:{}",parseObj.getStr("info"));
            throw exception(NONGMO_THIRD_API_FAIL);
        }
        JSONArray geocodes = parseObj.getJSONArray(dataKey);
        return JSONUtil.toList(geocodes,respClass);
    }


}

